package metamodel;

import antlr.TokenStreamException;
import antlr.RecognitionException;

import java.util.List;
import java.util.ArrayList;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import junit.framework.TestCase;
import metamodel.parser.PrefixClassResolver;
import metamodel.misc.GraphViz;

/**
 * Tests the resolution of recursive types..
 *
 * User: felix
 * Date: 18.06.2005
 */
public class RecursiveTreeTest extends TestCase {
    public static class Klazz {
        String name;
        List attributes;

        public Klazz(String name, List attributes) {
            this.name = name;
            this.attributes = attributes;
        }

        public String toString() {
            return "ClassNode "+name;
        }

        public Klazz() {
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public List getAttributes() {
            if (attributes==null){
                attributes=new ArrayList(4);
            }
            return attributes;
        }

        public void setAttributes(List attributes) {
            this.attributes = attributes;
        }
    }

    public static class Attribute {
        Klazz type;
        String name;

        public String toString() {
            return "Attribute "+name+":"+type;
        }

        public Attribute() {
        }

        public Attribute(Klazz type, String name) {
            this.type = type;
            this.name = name;
        }

        public Klazz getType() {
            return type;
        }

        public void setType(Klazz type) {
            this.type = type;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
    public void testResolution() throws TokenStreamException, RecognitionException {
        metamodel.ClassNode meta = createModel();
        assertEquals("class",meta.getLabel());
        assertEquals(meta,((ObjectReference)((CollectionRef)meta.getProperty("attributes")).getElementType().getProperty("type")).getElementType());
    }


    public void testRecursiveSerialisation() throws TokenStreamException, RecognitionException {
        metamodel.ClassNode meta = createModel();
        Object klazz = createData();

        String serialized = TraversalUtils.serialize(meta, klazz);

        assertEquals("(\"ContactInfo\",[(\"address\",(\"Address\",[(\"city\",null)]))])",serialized);
    }

    public void testSimpleRecursiveTraversal() throws TokenStreamException, RecognitionException {
        metamodel.ClassNode meta = createModel();
        Klazz klazz = createData();
        Object clone= TraversalUtils.clone(meta,klazz);
        assertTrue(TraversalUtils.equals(meta,klazz,clone));
    }

    private Klazz createData() {
        ArrayList attributes = new ArrayList();
        List addressAttributes=new ArrayList();
        addressAttributes.add(new Attribute(null,"city"));
        Klazz addressKlazz = new Klazz("Address",addressAttributes);
        attributes.add(new Attribute(addressKlazz,"address"));
        Klazz klazz =new Klazz("ContactInfo",attributes);
        return klazz;
    }

    private static metamodel.ClassNode createModel() throws RecognitionException, TokenStreamException {
        metamodel.ClassNode meta= TraversalUtils.parse("Klazz as class(" +
                "                                             name," +
                "                                             attributes:collection(" +
                "                                                 Attribute(" +
                "                                                        name," +
                "                                                        type:reference(class)" +
                "                                                 )" +
                "                                             )" +
                "                                   )");
        meta.setResolver(new PrefixClassResolver(new String[]{"metamodel.RecursiveTreeTest$"}));
        return meta;
    }

    public void testMetaMeta() throws TokenStreamException, RecognitionException, IOException {
        metamodel.ClassNode meta = TraversalUtils.createMetaModel();
        Object model=createModel();
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        Object clone= TraversalUtils.clone(meta,model);
    }

    public static void main(String[] args) throws IOException, TokenStreamException, RecognitionException {
        metamodel.ClassNode meta = TraversalUtils.createMetaModel();
        metamodel.ClassNode model=createModel();
        GraphViz.graph(meta,model,true, "Graph Test");
    }

}
